package com.link.gateway.core.filter.global;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.link.gateway.base.auth.model.Authclient;
import com.link.gateway.core.comproperty.*;
import com.link.gateway.core.utils.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * 校验权限
 *
 * @author huanglongjian
 * @date 2019年07月22日
 */
@Component
public class LinkCheckScopeGlobalFilter implements GlobalFilter, Ordered {
    private static final Logger logger = LogManager.getLogger(LinkCheckScopeGlobalFilter.class);

    /**
     * 校验请求的范围
     *
     * @author huanglongjian
     * @date 2019年07月22日
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //跳过检测
        Object ignoreGlobalFilter = exchange.getAttribute(OtherConstants.ATTRIBUTE_IGNORE_GLOBAL_FILTER);
        if (ignoreGlobalFilter != null && (boolean)ignoreGlobalFilter) {
            return chain.filter(exchange);
        }

        long begin = System.currentTimeMillis();
        ServerHttpRequest request = exchange.getRequest();
        //校验，如果是不拦截的请求，则直接略过
        if (TokenUtils.checkNoIntercept(request)) {
            return chain.filter(exchange);
        }

        String curClientId = RunProperties.CURRENT_CLIENT_ID.get();
        String scope = RunProperties.SCOPE.get();

        //若管理员从crm入口进来，则不校验范围
        if ("CRM".equalsIgnoreCase(scope) && UserUtil.isAdmin()) {
            return chain.filter(exchange);
        }
        String checkScopeFlag = null;
        try {
            Authclient authclient = CacheUtil.getAuthclientCache(curClientId);
            checkScopeFlag = authclient.getCheckScopeFlag();
        } catch (ExecutionException e) {
            logger.error(e.getMessage());
            return ResponseDataUtils.writeWith(InterfaceLogConstants.NORMAL, e.getMessage(), "Y", exchange, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        if ( !"Y".equals(checkScopeFlag)) {
            //如果当前企业没有开启校验范围，则直接略过
            return chain.filter(exchange);
        }

        //获取得到当前的url
        String requestUrl = request.getURI().getPath();
        Map<String, String> mapScope = null;
        try {
            mapScope = CacheUtil.getAllUrlScopeFromCache(TokenConstants.ALL_URL_SCOPE_CACHE_KEY);
        } catch (ExecutionException e) {
            logger.error(e.getMessage());
            return ResponseDataUtils.writeWith(InterfaceLogConstants.NORMAL,e.getMessage(), "Y",exchange, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        String socpeStr = mapScope.get(requestUrl);
        //如果 socpeStr 为空，可能是因为当前的url用了通配符，那么基于通配符在遍历一遍
        //因为有通配符的接口不多，所以单独考虑
        if (StringUtils.isEmpty(socpeStr)) {
            for (Map.Entry<String, String> map : mapScope.entrySet()) {
                AntPathMatcher antPathMatcher = new AntPathMatcher();
                if (antPathMatcher.match(map.getKey(), requestUrl)) {
                    socpeStr =  mapScope.get(map.getKey());
                }
            }
        }
        JSONObject jsonObject = JSON.parseObject(socpeStr);

        if (jsonObject == null || !"Y".equals(jsonObject.getString(scope))) {
            return ResponseDataUtils.writeWith(InterfaceLogConstants.SCOPE_OVER,"你没有权限访问该接口", "Y",exchange, HttpStatus.FORBIDDEN);
        }
        FunctionTimeUtil.functionTime("LinkCheckScopeGlobalFilterPre", "LinkCheckScopeGlobalFilter", begin, System.currentTimeMillis(), false);
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            FunctionTimeUtil.functionTime("LinkCheckScopeGlobalFilterPost", "LinkCheckScopeGlobalFilter", begin, System.currentTimeMillis(), false);
        }));
    }


    @Override
    public int getOrder() {
        return FilterOrderConstants.CHECK_SCOPE_ORDER;
    }
}
